From: Keir Fraser Date: Fri, 14 May 2010 14:22:48 +0000 (+0100) Subject: x86: Implement cpu hotplug notifiers. Use them. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~12159 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https:/%22bookmarks://%22Dat/%22http:/www.example.com/cgi/%22https:/%22bookmarks:/%22Dat?a=commitdiff_plain;h=2e4146ddc277d2ddd861646b8b1ba83182eb84bb;p=xen.git x86: Implement cpu hotplug notifiers. Use them. Signed-off-by: Keir Fraser --- diff --git a/xen/arch/ia64/xen/xen.lds.S b/xen/arch/ia64/xen/xen.lds.S index 547790f800..f642a93dc0 100644 --- a/xen/arch/ia64/xen/xen.lds.S +++ b/xen/arch/ia64/xen/xen.lds.S @@ -139,6 +139,8 @@ SECTIONS .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) { __initcall_start = .; + *(.initcallpresmp.init) + __presmp_initcall_end = .; *(.initcall1.init) *(.initcall2.init) *(.initcall3.init) diff --git a/xen/arch/ia64/xen/xensetup.c b/xen/arch/ia64/xen/xensetup.c index 82b758b788..a7e4791771 100644 --- a/xen/arch/ia64/xen/xensetup.c +++ b/xen/arch/ia64/xen/xensetup.c @@ -89,13 +89,6 @@ xen_count_pages(u64 start, u64 end, void *arg) return 0; } -static void __init do_initcalls(void) -{ - initcall_t *call; - for ( call = &__initcall_start; call < &__initcall_end; call++ ) - (*call)(); -} - /* * IPF loader only supports one command line currently, for * both xen and guest kernel. This function provides pre-parse @@ -612,15 +605,15 @@ skip_move: /* Enable IRQ to receive IPI (needed for ITC sync). */ local_irq_enable(); + do_presmp_initcalls(); + printk("num_online_cpus=%d, max_cpus=%d\n",num_online_cpus(),max_cpus); for_each_present_cpu ( i ) { if ( num_online_cpus() >= max_cpus ) break; - if ( !cpu_online(i) ) { - rcu_online_cpu(i); - __cpu_up(i); - } + if ( !cpu_online(i) ) + cpu_up(i); } local_irq_disable(); @@ -629,8 +622,6 @@ printk("num_online_cpus=%d, max_cpus=%d\n",num_online_cpus(),max_cpus); smp_cpus_done(max_cpus); #endif - initialise_gdb(); /* could be moved earlier */ - iommu_setup(); /* setup iommu if available */ do_initcalls(); diff --git a/xen/arch/x86/cpu/mcheck/mce_intel.c b/xen/arch/x86/cpu/mcheck/mce_intel.c index ccd1d7da9f..21c756c366 100644 --- a/xen/arch/x86/cpu/mcheck/mce_intel.c +++ b/xen/arch/x86/cpu/mcheck/mce_intel.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -788,7 +789,7 @@ static void __cpu_mcheck_distribute_cmci(void *unused) cmci_discover(); } -void cpu_mcheck_distribute_cmci(void) +static void cpu_mcheck_distribute_cmci(void) { if (cmci_support && !mce_disabled) on_each_cpu(__cpu_mcheck_distribute_cmci, NULL, 0); @@ -816,7 +817,7 @@ static void clear_cmci(void) } } -void cpu_mcheck_disable(void) +static void cpu_mcheck_disable(void) { clear_in_cr4(X86_CR4_MCE); @@ -1007,4 +1008,31 @@ int intel_mce_rdmsr(uint32_t msr, uint64_t *val) return ret; } +static int cpu_callback( + struct notifier_block *nfb, unsigned long action, void *hcpu) +{ + switch ( action ) + { + case CPU_DYING: + cpu_mcheck_disable(); + break; + case CPU_DEAD: + cpu_mcheck_distribute_cmci(); + break; + default: + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block cpu_nfb = { + .notifier_call = cpu_callback +}; + +static int __init intel_mce_initcall(void) +{ + register_cpu_notifier(&cpu_nfb); + return 0; +} +presmp_initcall(intel_mce_initcall); diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 2570e77b14..57b54f21be 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 9d86b85ae9..cfa0643f95 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,28 @@ struct hvm_function_table hvm_funcs __read_mostly; unsigned long __attribute__ ((__section__ (".bss.page_aligned"))) hvm_io_bitmap[3*PAGE_SIZE/BYTES_PER_LONG]; +static int cpu_callback( + struct notifier_block *nfb, unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + int rc = 0; + + switch ( action ) + { + case CPU_UP_PREPARE: + rc = hvm_funcs.cpu_prepare(cpu); + break; + default: + break; + } + + return !rc ? NOTIFY_DONE : notifier_from_errno(rc); +} + +static struct notifier_block cpu_nfb = { + .notifier_call = cpu_callback +}; + void hvm_enable(struct hvm_function_table *fns) { extern int hvm_port80_allowed; @@ -91,6 +114,8 @@ void hvm_enable(struct hvm_function_table *fns) if ( hvm_funcs.hap_supported ) printk("HVM: Hardware Assisted Paging detected.\n"); + + register_cpu_notifier(&cpu_nfb); } /* diff --git a/xen/arch/x86/platform_hypercall.c b/xen/arch/x86/platform_hypercall.c index 67a5fbb73c..b3ab4b7446 100644 --- a/xen/arch/x86/platform_hypercall.c +++ b/xen/arch/x86/platform_hypercall.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include diff --git a/xen/arch/x86/setup.c b/xen/arch/x86/setup.c index 4eabbbf6e4..d6c07f0895 100644 --- a/xen/arch/x86/setup.c +++ b/xen/arch/x86/setup.c @@ -156,13 +156,6 @@ static void __init parse_acpi_param(char *s) } } -static void __init do_initcalls(void) -{ - initcall_t *call; - for ( call = &__initcall_start; call < &__initcall_end; call++ ) - (*call)(); -} - #define EARLY_FAIL(f, a...) do { \ printk( f , ## a ); \ for ( ; ; ) halt(); \ @@ -1070,15 +1063,14 @@ void __init __start_xen(unsigned long mbi_p) console_init_postirq(); + do_presmp_initcalls(); + for_each_present_cpu ( i ) { if ( num_online_cpus() >= max_cpus ) break; if ( !cpu_online(i) ) - { - rcu_online_cpu(i); - __cpu_up(i); - } + cpu_up(i); /* Set up cpu_to_node[]. */ srat_detect_node(i); @@ -1089,8 +1081,6 @@ void __init __start_xen(unsigned long mbi_p) printk("Brought up %ld CPUs\n", (long)num_online_cpus()); smp_cpus_done(max_cpus); - initialise_gdb(); /* could be moved earlier */ - do_initcalls(); if ( opt_watchdog ) @@ -1099,11 +1089,6 @@ void __init __start_xen(unsigned long mbi_p) if ( !tboot_protect_mem_regions() ) panic("Could not protect TXT memory regions\n"); - /* Create initial cpupool 0. */ - cpupool0 = cpupool_create(0, NULL); - if ( (cpupool0 == NULL) || cpupool0_cpu_assign(cpupool0) ) - panic("Error creating cpupool 0\n"); - /* Create initial domain 0. */ dom0 = domain_create(0, DOMCRF_s3_integrity, DOM0_SSIDREF); if ( (dom0 == NULL) || (alloc_dom0_vcpu0() == NULL) ) diff --git a/xen/arch/x86/smpboot.c b/xen/arch/x86/smpboot.c index b6583fe4ab..8b857b3809 100644 --- a/xen/arch/x86/smpboot.c +++ b/xen/arch/x86/smpboot.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -106,7 +107,6 @@ static void map_cpu_to_logical_apicid(void); DEFINE_PER_CPU(int, cpu_state) = { 0 }; void *stack_base[NR_CPUS]; -DEFINE_SPINLOCK(cpu_add_remove_lock); /* * The bootstrap kernel entry code has set these up. Save them for @@ -1272,17 +1272,6 @@ int __cpu_disable(void) { int cpu = smp_processor_id(); - /* - * Perhaps use cpufreq to drop frequency, but that could go - * into generic code. - * - * We won't take down the boot processor on i386 due to some - * interrupts only being able to be serviced by the BSP. - * Especially so if we're not using an IOAPIC -zwane - */ - if (cpu == 0) - return -EBUSY; - local_irq_disable(); clear_local_APIC(); /* Allow any queued timer interrupts to get serviced */ @@ -1292,8 +1281,6 @@ int __cpu_disable(void) time_suspend(); - cpu_mcheck_disable(); - remove_siblinginfo(cpu); /* It's now safe to remove this processor from the online map */ @@ -1313,10 +1300,8 @@ void __cpu_die(unsigned int cpu) for (;;) { /* They ack this in play_dead by setting CPU_DEAD */ - if (per_cpu(cpu_state, cpu) == CPU_DEAD) { - printk ("CPU %u is now offline\n", cpu); + if (per_cpu(cpu_state, cpu) == CPU_DEAD) return; - } mdelay(100); mb(); process_pending_softirqs(); @@ -1327,7 +1312,19 @@ void __cpu_die(unsigned int cpu) static int take_cpu_down(void *unused) { - return __cpu_disable(); + void *hcpu = (void *)(long)smp_processor_id(); + int rc; + + spin_lock(&cpu_add_remove_lock); + + if (cpu_notifier_call_chain(CPU_DYING, hcpu) != NOTIFY_DONE) + BUG(); + + rc = __cpu_disable(); + + spin_unlock(&cpu_add_remove_lock); + + return rc; } /* @@ -1339,7 +1336,8 @@ static cpumask_t cpu_offlining; int cpu_down(unsigned int cpu) { - int err = 0; + int err, notifier_rc, nr_calls; + void *hcpu = (void *)(long)cpu; spin_lock(&cpu_add_remove_lock); @@ -1350,32 +1348,42 @@ int cpu_down(unsigned int cpu) cpu_set(cpu, cpu_offlining); - err = cpupool_cpu_remove(cpu); - if (err) - goto out; - printk("Prepare to bring CPU%d down...\n", cpu); - cpufreq_del_cpu(cpu); + notifier_rc = __cpu_notifier_call_chain( + CPU_DOWN_PREPARE, hcpu, -1, &nr_calls); + if (notifier_rc != NOTIFY_DONE) { + err = notifier_to_errno(notifier_rc); + nr_calls--; + notifier_rc = __cpu_notifier_call_chain( + CPU_DOWN_FAILED, hcpu, nr_calls, NULL); + BUG_ON(notifier_rc != NOTIFY_DONE); + goto out; + } spin_unlock(&cpu_add_remove_lock); err = stop_machine_run(take_cpu_down, NULL, cpu); spin_lock(&cpu_add_remove_lock); if (err < 0) { - cpupool_cpu_add(cpu); + notifier_rc = cpu_notifier_call_chain(CPU_DOWN_FAILED, hcpu); + BUG_ON(notifier_rc != NOTIFY_DONE); goto out; } __cpu_die(cpu); BUG_ON(cpu_online(cpu)); - migrate_tasklets_from_cpu(cpu); - cpu_mcheck_distribute_cmci(); + notifier_rc = cpu_notifier_call_chain(CPU_DEAD, hcpu); + BUG_ON(notifier_rc != NOTIFY_DONE); out: - if (!err) + if (!err) { + printk("CPU %u is now offline\n", cpu); send_guest_global_virq(dom0, VIRQ_PCPU_STATE); + } else { + printk("Failed to take down CPU %u (error %d)\n", cpu, err); + } cpu_clear(cpu, cpu_offlining); spin_unlock(&cpu_add_remove_lock); return err; @@ -1392,8 +1400,6 @@ int cpu_up(unsigned int cpu) goto out; } - rcu_online_cpu(cpu); - err = __cpu_up(cpu); if (err < 0) goto out; @@ -1525,11 +1531,16 @@ int cpu_add(uint32_t apic_id, uint32_t acpi_id, uint32_t pxm) int __devinit __cpu_up(unsigned int cpu) { - int ret; - - ret = hvm_cpu_prepare(cpu); - if (ret) - return ret; + int notifier_rc, ret = 0, nr_calls; + void *hcpu = (void *)(long)cpu; + + notifier_rc = __cpu_notifier_call_chain( + CPU_UP_PREPARE, hcpu, -1, &nr_calls); + if (notifier_rc != NOTIFY_DONE) { + ret = notifier_to_errno(notifier_rc); + nr_calls--; + goto fail; + } /* * We do warm boot only on cpus that had booted earlier @@ -1542,18 +1553,18 @@ int __devinit __cpu_up(unsigned int cpu) smpboot_restore_warm_reset_vector(); } - if (ret) - return -EIO; + if (ret) { + ret = -EIO; + goto fail; + } /* In case one didn't come up */ if (!cpu_isset(cpu, cpu_callin_map)) { printk(KERN_DEBUG "skipping cpu%d, didn't come online\n", cpu); - local_irq_enable(); - return -EIO; + ret = -EIO; + goto fail; } - local_irq_enable(); - /*per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;*/ /* Unleash the CPU! */ cpu_set(cpu, smp_commenced_mask); while (!cpu_isset(cpu, cpu_online_map)) { @@ -1561,9 +1572,15 @@ int __devinit __cpu_up(unsigned int cpu) process_pending_softirqs(); } - cpupool_cpu_add(cpu); - cpufreq_add_cpu(cpu); + notifier_rc = cpu_notifier_call_chain(CPU_ONLINE, hcpu); + BUG_ON(notifier_rc != NOTIFY_DONE); return 0; + + fail: + notifier_rc = __cpu_notifier_call_chain( + CPU_UP_CANCELED, hcpu, nr_calls, NULL); + BUG_ON(notifier_rc != NOTIFY_DONE); + return ret; } diff --git a/xen/arch/x86/xen.lds.S b/xen/arch/x86/xen.lds.S index 20f9f2dca4..31ac018e71 100644 --- a/xen/arch/x86/xen.lds.S +++ b/xen/arch/x86/xen.lds.S @@ -89,6 +89,8 @@ SECTIONS } :text .initcall.init : { __initcall_start = .; + *(.initcallpresmp.init) + __presmp_initcall_end = .; *(.initcall1.init) __initcall_end = .; } :text diff --git a/xen/common/cpu.c b/xen/common/cpu.c index 96cba72e9e..8a04dd449e 100644 --- a/xen/common/cpu.c +++ b/xen/common/cpu.c @@ -1,5 +1,6 @@ #include #include +#include /* * cpu_bit_bitmap[] is a special, "compressed" data structure that @@ -24,3 +25,36 @@ const unsigned long cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)] = { MASK_DECLARE_8(48), MASK_DECLARE_8(56), #endif }; + +DEFINE_SPINLOCK(cpu_add_remove_lock); + +static RAW_NOTIFIER_HEAD(cpu_chain); + +int register_cpu_notifier(struct notifier_block *nb) +{ + int ret; + spin_lock(&cpu_add_remove_lock); + ret = raw_notifier_chain_register(&cpu_chain, nb); + spin_unlock(&cpu_add_remove_lock); + return ret; +} + +void unregister_cpu_notifier(struct notifier_block *nb) +{ + spin_lock(&cpu_add_remove_lock); + raw_notifier_chain_unregister(&cpu_chain, nb); + spin_unlock(&cpu_add_remove_lock); +} + +int cpu_notifier_call_chain(unsigned long val, void *v) +{ + BUG_ON(!spin_is_locked(&cpu_add_remove_lock)); + return raw_notifier_call_chain(&cpu_chain, val, v); +} + +int __cpu_notifier_call_chain( + unsigned long val, void *v, int nr_to_call, int *nr_calls) +{ + BUG_ON(!spin_is_locked(&cpu_add_remove_lock)); + return __raw_notifier_call_chain(&cpu_chain, val, v, nr_to_call, nr_calls); +} diff --git a/xen/common/cpupool.c b/xen/common/cpupool.c index 8c049c1830..e8301f466c 100644 --- a/xen/common/cpupool.c +++ b/xen/common/cpupool.c @@ -17,6 +17,7 @@ #include #include #include +#include #define for_each_cpupool(ptr) \ for ((ptr) = &cpupool_list; *(ptr) != NULL; (ptr) = &((*(ptr))->next)) @@ -178,10 +179,8 @@ static int cpupool_assign_cpu_locked(struct cpupool *c, unsigned int cpu) */ int cpupool_assign_ncpu(struct cpupool *c, int ncpu) { - int i; - int n; + int i, n = 0; - n = 0; spin_lock(&cpupool_lock); for_each_cpu_mask(i, cpupool_free_cpus) { @@ -293,21 +292,6 @@ out: return ret; } -/* - * assign cpus to the default cpupool - * default are all cpus, less cpus may be specified as boot parameter - * possible failures: - * - no cpu assigned - */ -int __init cpupool0_cpu_assign(struct cpupool *c) -{ - if ( (cpupool0_max_cpus == 0) || (cpupool0_max_cpus > num_online_cpus()) ) - cpupool0_max_cpus = num_online_cpus(); - if ( !cpupool_assign_ncpu(cpupool0, cpupool0_max_cpus) ) - return 1; - return 0; -} - /* * add a new domain to a cpupool * possible failures: @@ -363,16 +347,14 @@ void cpupool_rm_domain(struct domain *d) * called to add a new cpu to pool admin * we add a hotplugged cpu to the cpupool0 to be able to add it to dom0 */ -void cpupool_cpu_add(unsigned int cpu) +static void cpupool_cpu_add(unsigned int cpu) { - if ( cpupool0 == NULL ) - return; spin_lock(&cpupool_lock); cpu_clear(cpu, cpupool_locked_cpus); cpu_set(cpu, cpupool_free_cpus); - cpupool_assign_cpu_locked(cpupool0, cpu); + if ( cpupool0 != NULL ) + cpupool_assign_cpu_locked(cpupool0, cpu); spin_unlock(&cpupool_lock); - return; } /* @@ -380,7 +362,7 @@ void cpupool_cpu_add(unsigned int cpu) * the cpu to be removed is locked to avoid removing it from dom0 * returns failure if not in pool0 */ -int cpupool_cpu_remove(unsigned int cpu) +static int cpupool_cpu_remove(unsigned int cpu) { int ret = 0; @@ -588,10 +570,52 @@ void dump_runq(unsigned char key) spin_unlock(&cpupool_lock); } +static int cpu_callback( + struct notifier_block *nfb, unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + int rc = 0; + + switch ( action ) + { + case CPU_DOWN_FAILED: + case CPU_ONLINE: + cpupool_cpu_add(cpu); + break; + case CPU_DOWN_PREPARE: + rc = cpupool_cpu_remove(cpu); + break; + default: + break; + } + + return !rc ? NOTIFY_DONE : notifier_from_errno(rc); +} + +static struct notifier_block cpu_nfb = { + .notifier_call = cpu_callback +}; + +static int __init cpupool_presmp_init(void) +{ + void *cpu = (void *)(long)smp_processor_id(); + cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); + register_cpu_notifier(&cpu_nfb); + return 0; +} +presmp_initcall(cpupool_presmp_init); + static int __init cpupool_init(void) { - cpupool_free_cpus = cpu_online_map; - cpupool_list = NULL; + cpupool0 = cpupool_create(0, NULL); + BUG_ON(cpupool0 == NULL); + + if ( (cpupool0_max_cpus == 0) || (cpupool0_max_cpus > num_online_cpus()) ) + cpupool0_max_cpus = num_online_cpus(); + + if ( !cpupool_assign_ncpu(cpupool0, cpupool0_max_cpus) ) + BUG(); + return 0; } __initcall(cpupool_init); diff --git a/xen/common/gdbstub.c b/xen/common/gdbstub.c index cf03139d7f..51129206bf 100644 --- a/xen/common/gdbstub.c +++ b/xen/common/gdbstub.c @@ -44,6 +44,7 @@ #include #include #include +#include #include /* Printk isn't particularly safe just after we've trapped to the @@ -639,23 +640,25 @@ __trap_to_gdb(struct cpu_user_regs *regs, unsigned long cookie) return rc; } -void __init -initialise_gdb(void) +static int __init initialise_gdb(void) { if ( *opt_gdb == '\0' ) - return; + return 0; gdb_ctx->serhnd = serial_parse_handle(opt_gdb); if ( gdb_ctx->serhnd == -1 ) { printk("Bad gdb= option '%s'\n", opt_gdb); - return; + return 0; } serial_start_sync(gdb_ctx->serhnd); printk("GDB stub initialised.\n"); + + return 0; } +presmp_initcall(initialise_gdb); static void gdb_pause_this_cpu(void *unused) { diff --git a/xen/common/kernel.c b/xen/common/kernel.c index 3a0c40fce4..61a798df4e 100644 --- a/xen/common/kernel.c +++ b/xen/common/kernel.c @@ -147,6 +147,22 @@ void add_taint(unsigned flag) tainted |= flag; } +extern initcall_t __initcall_start, __presmp_initcall_end, __initcall_end; + +void __init do_presmp_initcalls(void) +{ + initcall_t *call; + for ( call = &__initcall_start; call < &__presmp_initcall_end; call++ ) + (*call)(); +} + +void __init do_initcalls(void) +{ + initcall_t *call; + for ( call = &__presmp_initcall_end; call < &__initcall_end; call++ ) + (*call)(); +} + # define DO(fn) long do_##fn #endif diff --git a/xen/common/notifier.c b/xen/common/notifier.c index 320bca0b58..fe1c507a7a 100644 --- a/xen/common/notifier.c +++ b/xen/common/notifier.c @@ -65,6 +65,9 @@ static int notifier_call_chain( int ret = NOTIFY_DONE; struct notifier_block *nb, *next_nb; + if ( nr_calls ) + *nr_calls = 0; + nb = rcu_dereference(*nl); while ( nb && nr_to_call ) diff --git a/xen/common/rcupdate.c b/xen/common/rcupdate.c index 676da1efe5..31c5f6f39b 100644 --- a/xen/common/rcupdate.c +++ b/xen/common/rcupdate.c @@ -43,6 +43,7 @@ #include #include #include +#include /* Definition for rcupdate control block. */ struct rcu_ctrlblk rcu_ctrlblk = { @@ -334,15 +335,33 @@ static void rcu_init_percpu_data(int cpu, struct rcu_ctrlblk *rcp, rdp->blimit = blimit; } -void __devinit rcu_online_cpu(int cpu) +static int cpu_callback( + struct notifier_block *nfb, unsigned long action, void *hcpu) { - struct rcu_data *rdp = &per_cpu(rcu_data, cpu); + unsigned int cpu = (unsigned long)hcpu; + + switch ( action ) + { + case CPU_UP_PREPARE: { + struct rcu_data *rdp = &per_cpu(rcu_data, cpu); + rcu_init_percpu_data(cpu, &rcu_ctrlblk, rdp); + break; + } + default: + break; + } - rcu_init_percpu_data(cpu, &rcu_ctrlblk, rdp); + return NOTIFY_DONE; } +static struct notifier_block cpu_nfb = { + .notifier_call = cpu_callback +}; + void __init rcu_init(void) { - rcu_online_cpu(smp_processor_id()); + void *cpu = (void *)(long)smp_processor_id(); + cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); + register_cpu_notifier(&cpu_nfb); open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); } diff --git a/xen/common/tasklet.c b/xen/common/tasklet.c index 7a6717e55b..f9b889d717 100644 --- a/xen/common/tasklet.c +++ b/xen/common/tasklet.c @@ -16,9 +16,10 @@ #include #include #include +#include /* Some subsystems call into us before we are initialised. We ignore them. */ -static bool_t tasklets_initialised; +static cpumask_t tasklets_initialised; DEFINE_PER_CPU(unsigned long, tasklet_work_to_do); @@ -43,7 +44,7 @@ void tasklet_schedule_on_cpu(struct tasklet *t, unsigned int cpu) spin_lock_irqsave(&tasklet_lock, flags); - if ( tasklets_initialised && !t->is_dead ) + if ( cpu_isset(cpu, tasklets_initialised) && !t->is_dead ) { t->scheduled_on = cpu; if ( !t->is_running ) @@ -135,7 +136,7 @@ void tasklet_kill(struct tasklet *t) spin_unlock_irqrestore(&tasklet_lock, flags); } -void migrate_tasklets_from_cpu(unsigned int cpu) +static void migrate_tasklets_from_cpu(unsigned int cpu) { struct list_head *list = &per_cpu(tasklet_list, cpu); unsigned long flags; @@ -165,14 +166,36 @@ void tasklet_init( t->data = data; } -void __init tasklet_subsys_init(void) +static int cpu_callback( + struct notifier_block *nfb, unsigned long action, void *hcpu) { - unsigned int cpu; + unsigned int cpu = (unsigned long)hcpu; + + switch ( action ) + { + case CPU_UP_PREPARE: + if ( !cpu_test_and_set(cpu, tasklets_initialised) ) + INIT_LIST_HEAD(&per_cpu(tasklet_list, cpu)); + break; + case CPU_DEAD: + migrate_tasklets_from_cpu(cpu); + break; + default: + break; + } - for_each_possible_cpu ( cpu ) - INIT_LIST_HEAD(&per_cpu(tasklet_list, cpu)); + return NOTIFY_DONE; +} + +static struct notifier_block cpu_nfb = { + .notifier_call = cpu_callback +}; - tasklets_initialised = 1; +void __init tasklet_subsys_init(void) +{ + void *hcpu = (void *)(long)smp_processor_id(); + cpu_callback(&cpu_nfb, CPU_UP_PREPARE, hcpu); + register_cpu_notifier(&cpu_nfb); } /* diff --git a/xen/drivers/cpufreq/cpufreq.c b/xen/drivers/cpufreq/cpufreq.c index 627435d88c..d81a952815 100644 --- a/xen/drivers/cpufreq/cpufreq.c +++ b/xen/drivers/cpufreq/cpufreq.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -582,3 +583,38 @@ void __init cpufreq_cmdline_parse(char *str) str = end; } while (str); } + +static int cpu_callback( + struct notifier_block *nfb, unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + + switch ( action ) + { + case CPU_DOWN_FAILED: + case CPU_ONLINE: + (void)cpufreq_add_cpu(cpu); + break; + case CPU_DOWN_PREPARE: + (void)cpufreq_del_cpu(cpu); + break; + default: + break; + } + + return NOTIFY_DONE; +} + +static struct notifier_block cpu_nfb = { + .notifier_call = cpu_callback +}; + +static int __init cpufreq_presmp_init(void) +{ + void *cpu = (void *)(long)smp_processor_id(); + cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); + register_cpu_notifier(&cpu_nfb); + return 0; +} +presmp_initcall(cpufreq_presmp_init); + diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h index 58a27e738f..e5d3fdbab6 100644 --- a/xen/include/asm-x86/hvm/hvm.h +++ b/xen/include/asm-x86/hvm/hvm.h @@ -295,12 +295,6 @@ uint8_t hvm_combine_hw_exceptions(uint8_t vec1, uint8_t vec2); void hvm_set_rdtsc_exiting(struct domain *d, bool_t enable); -static inline int -hvm_cpu_prepare(unsigned int cpu) -{ - return (hvm_funcs.cpu_prepare ? hvm_funcs.cpu_prepare(cpu) : 0); -} - static inline int hvm_cpu_up(void) { return (hvm_funcs.cpu_up ? hvm_funcs.cpu_up() : 1); diff --git a/xen/include/asm-x86/processor.h b/xen/include/asm-x86/processor.h index a17eb93c42..03791206aa 100644 --- a/xen/include/asm-x86/processor.h +++ b/xen/include/asm-x86/processor.h @@ -551,8 +551,6 @@ extern void mtrr_bp_init(void); void mcheck_init(struct cpuinfo_x86 *c); asmlinkage void do_machine_check(struct cpu_user_regs *regs); -void cpu_mcheck_distribute_cmci(void); -void cpu_mcheck_disable(void); int cpuid_hypervisor_leaves( uint32_t idx, uint32_t sub_idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx); diff --git a/xen/include/asm-x86/smp.h b/xen/include/asm-x86/smp.h index 6f5200dbed..d67165493a 100644 --- a/xen/include/asm-x86/smp.h +++ b/xen/include/asm-x86/smp.h @@ -53,10 +53,7 @@ extern u32 cpu_2_logical_apicid[]; #define cpu_physical_id(cpu) x86_cpu_to_apicid[cpu] /* State of each CPU. */ -#define CPU_ONLINE 0x0002 /* CPU is up */ -#define CPU_DEAD 0x0004 /* CPU is dead */ DECLARE_PER_CPU(int, cpu_state); -extern spinlock_t(cpu_add_remove_lock); #define cpu_is_offline(cpu) unlikely(!cpu_online(cpu)) extern int cpu_down(unsigned int cpu); diff --git a/xen/include/xen/cpu.h b/xen/include/xen/cpu.h new file mode 100644 index 0000000000..521559e6bb --- /dev/null +++ b/xen/include/xen/cpu.h @@ -0,0 +1,28 @@ +#ifndef __XEN_CPU_H__ +#define __XEN_CPU_H__ + +#include +#include +#include + +extern spinlock_t cpu_add_remove_lock; + +int register_cpu_notifier(struct notifier_block *nb); +void unregister_cpu_notifier(struct notifier_block *nb); +int cpu_notifier_call_chain(unsigned long val, void *v); +int __cpu_notifier_call_chain( + unsigned long val, void *v, int nr_to_call, int *nr_calls); + +/* + * Notification actions: note that only CPU_{UP,DOWN}_PREPARE may fail --- + * all other handlers *must* return NOTIFY_DONE. + */ +#define CPU_UP_PREPARE 0x0002 /* CPU is coming up */ +#define CPU_UP_CANCELED 0x0003 /* CPU is no longer coming up */ +#define CPU_ONLINE 0x0004 /* CPU is up */ +#define CPU_DOWN_PREPARE 0x0005 /* CPU is going down */ +#define CPU_DOWN_FAILED 0x0006 /* CPU is no longer going down */ +#define CPU_DYING 0x0007 /* CPU is nearly dead (in stop_machine ctxt) */ +#define CPU_DEAD 0x0008 /* CPU is dead */ + +#endif /* __XEN_CPU_H__ */ diff --git a/xen/include/xen/gdbstub.h b/xen/include/xen/gdbstub.h index e9f0cd5a27..7ff9dd80a0 100644 --- a/xen/include/xen/gdbstub.h +++ b/xen/include/xen/gdbstub.h @@ -88,12 +88,6 @@ void gdb_arch_exit(struct cpu_user_regs *regs); #define SIGALRM 14 #define SIGTERM 15 -void initialise_gdb(void); - -#else - -#define initialise_gdb() ((void)0) - #endif #endif /* __XEN_GDBSTUB_H__ */ diff --git a/xen/include/xen/init.h b/xen/include/xen/init.h index fdfdb55835..220d464fc7 100644 --- a/xen/include/xen/init.h +++ b/xen/include/xen/init.h @@ -18,8 +18,8 @@ __attribute_used__ __attribute__ ((__section__ (".exit.data"))) #define __initsetup \ __attribute_used__ __attribute__ ((__section__ (".init.setup"))) -#define __init_call \ - __attribute_used__ __attribute__ ((__section__ (".initcall1.init"))) +#define __init_call(lvl) \ + __attribute_used__ __attribute__ ((__section__ (".initcall" lvl ".init"))) #define __exit_call \ __attribute_used__ __attribute__ ((__section__ (".exitcall.exit"))) @@ -66,13 +66,16 @@ typedef int (*initcall_t)(void); typedef void (*exitcall_t)(void); -extern initcall_t __initcall_start, __initcall_end; - +#define presmp_initcall(fn) \ + static initcall_t __initcall_##fn __init_call("presmp") = fn #define __initcall(fn) \ - static initcall_t __initcall_##fn __init_call = fn + static initcall_t __initcall_##fn __init_call("1") = fn #define __exitcall(fn) \ static exitcall_t __exitcall_##fn __exit_call = fn +void do_presmp_initcalls(void); +void do_initcalls(void); + /* * Used for kernel command line parameter setup */ diff --git a/xen/include/xen/notifier.h b/xen/include/xen/notifier.h index 84ec50f92b..a827653849 100644 --- a/xen/include/xen/notifier.h +++ b/xen/include/xen/notifier.h @@ -52,38 +52,21 @@ int __raw_notifier_call_chain( struct raw_notifier_head *nh, unsigned long val, void *v, int nr_to_call, int *nr_calls); -#define NOTIFY_DONE 0x0000 /* Don't care */ -#define NOTIFY_OK 0x0001 /* Suits me */ -#define NOTIFY_STOP_MASK 0x8000 /* Don't call further */ -#define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) -/* Bad/Veto action */ -/* - * Clean way to return from the notifier and stop further calls. - */ -#define NOTIFY_STOP (NOTIFY_OK|NOTIFY_STOP_MASK) +#define NOTIFY_DONE 0x0000 +#define NOTIFY_STOP_MASK 0x8000 +#define NOTIFY_STOP (NOTIFY_STOP_MASK|NOTIFY_DONE) +#define NOTIFY_BAD (NOTIFY_STOP_MASK|EINVAL) -/* Encapsulate (negative) errno value (in particular, NOTIFY_BAD <=> EPERM). */ +/* Encapsulate (negative) errno value. */ static inline int notifier_from_errno(int err) { - return NOTIFY_STOP_MASK | (NOTIFY_OK - err); + return NOTIFY_STOP_MASK | -err; } /* Restore (negative) errno value from notify return value. */ static inline int notifier_to_errno(int ret) { - ret &= ~NOTIFY_STOP_MASK; - return ret > NOTIFY_OK ? NOTIFY_OK - ret : 0; + return -(ret & ~NOTIFY_STOP_MASK); } -#define CPU_ONLINE 0x0002 /* CPU (unsigned)v is up */ -#define CPU_UP_PREPARE 0x0003 /* CPU (unsigned)v coming up */ -#define CPU_UP_CANCELED 0x0004 /* CPU (unsigned)v NOT coming up */ -#define CPU_DOWN_PREPARE 0x0005 /* CPU (unsigned)v going down */ -#define CPU_DOWN_FAILED 0x0006 /* CPU (unsigned)v NOT going down */ -#define CPU_DEAD 0x0007 /* CPU (unsigned)v dead */ -#define CPU_DYING 0x0008 /* CPU (unsigned)v not running any task, - * not handling interrupts, soon dead */ -#define CPU_POST_DEAD 0x0009 /* CPU (unsigned)v dead, cpu_hotplug - * lock is dropped */ - #endif /* __XEN_NOTIFIER_H__ */ diff --git a/xen/include/xen/rcupdate.h b/xen/include/xen/rcupdate.h index 587a32e2b7..285e574e28 100644 --- a/xen/include/xen/rcupdate.h +++ b/xen/include/xen/rcupdate.h @@ -190,7 +190,6 @@ typedef struct _rcu_read_lock rcu_read_lock_t; #define rcu_assign_pointer(p, v) ({ smp_wmb(); (p) = (v); }) void rcu_init(void); -void __devinit rcu_online_cpu(int cpu); void rcu_check_callbacks(int cpu); /* Exported interfaces */ diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 4bcc7f1bf2..a8e086521a 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -622,10 +622,7 @@ extern enum cpufreq_controller { struct cpupool *cpupool_create(int poolid, char *sched); int cpupool_destroy(struct cpupool *c); -int cpupool0_cpu_assign(struct cpupool *c); int cpupool_assign_ncpu(struct cpupool *c, int ncpu); -void cpupool_cpu_add(unsigned int cpu); -int cpupool_cpu_remove(unsigned int cpu); int cpupool_add_domain(struct domain *d, int poolid); void cpupool_rm_domain(struct domain *d); int cpupool_do_sysctl(struct xen_sysctl_cpupool_op *op); diff --git a/xen/include/xen/tasklet.h b/xen/include/xen/tasklet.h index d324fb39c1..e8d6e96b0f 100644 --- a/xen/include/xen/tasklet.h +++ b/xen/include/xen/tasklet.h @@ -35,7 +35,6 @@ void tasklet_schedule_on_cpu(struct tasklet *t, unsigned int cpu); void tasklet_schedule(struct tasklet *t); void do_tasklet(void); void tasklet_kill(struct tasklet *t); -void migrate_tasklets_from_cpu(unsigned int cpu); void tasklet_init( struct tasklet *t, void (*func)(unsigned long), unsigned long data); void tasklet_subsys_init(void);